#pragma once

// Dependencies
namespace Core {
	template<class T> class Point3_t;
}

namespace Core {
	// Quaternion4_t -- Use Quaternion4 or Quaternion4f
	// Represents a rotation about an arbitrary axis
	// (Use of any Ts other than double or float will require
	// an explicit instantiation in Quaternion.cpp for that type)
	template<class T>
	class Quaternion4_t {
	public: // Typedefs
		typedef T value_type;
		typedef Quaternion4_t<T> this_type;

	public: // Constructors
		Quaternion4_t();
		Quaternion4_t( T x, T y, T z, T w );
		Quaternion4_t( const T (&arr)[4] );
	
	public: // Named constructors
		static Quaternion4_t<T> fromEuler( T pitch, T yaw, T roll );

	public: // Operators
		const Quaternion4_t<T> operator + ( const Quaternion4_t<T>& q ) const;
		const Quaternion4_t<T> operator - ( const Quaternion4_t<T>& q ) const;
		const Quaternion4_t<T> operator * ( const Quaternion4_t<T>& q ) const;
		const Quaternion4_t<T> operator * ( T s ) const;
		const Quaternion4_t<T> operator / ( T s ) const;
	
		Quaternion4_t<T>& operator += ( const Quaternion4_t<T>& q );
		Quaternion4_t<T>& operator -= ( const Quaternion4_t<T>& q );
		Quaternion4_t<T>& operator *= ( const Quaternion4_t<T>& q );
		Quaternion4_t<T>& operator *= ( T s );
		Quaternion4_t<T>& operator /= ( T s );

	public: // Methods
		T dot( const Quaternion4_t<T>& quat ) const;
		T sqLength() const;
		T length() const;
		const Quaternion4_t<T> normalized() const;
		Quaternion4_t<T>& normalize();

		void toMatrix4( T mat[4][4] ) const;

	public: // Accessors
		const T& operator[] ( int idx ) const;
		T& operator[] ( int idx );
		
	private: // Helper members
		// Maps an integer index to a member variable
		// (map is a static and constant 4-element array of pointer-to-T-typed members of Quaternion4_t<T>)
		static T Quaternion4_t::* const (map[4]);

	public: // Members
		T x, y, z, w;
	};

	// Typedefs available to the Core namespace
	typedef Quaternion4_t<float> Quaternion4f; 
	typedef Quaternion4_t<double> Quaternion4;
} // namespace Core